// Copyright (c) Duende Software. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;

namespace Duende.IdentityModel.OidcClient.Infrastructure;

public static class Crypto
{
    static Crypto() => IdentityModelEventSource.ShowPII = true;

    public static string UntrustedIdentityToken = "eyJhbGciOiJSUzI1NiIsImtpZCI6Ijk4RDNBQ0YwNTcyOTlDMzc0NTA0NEJFOTE4OTg2QUQ3RUQwQUQ0QTIiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJtTk9zOEZjcG5EZEZCRXZwR0pocTEtMEsxS0kifQ.eyJuYmYiOjE0ODQyOTc1MjksImV4cCI6MTQ4NDI5NzgyOSwiaXNzIjoiaHR0cHM6Ly9kZW1vLmlkZW50aXR5c2VydmVyLmlvIiwiYXVkIjoibmF0aXZlLmh5YnJpZCIsIm5vbmNlIjoiMjcwODQ5YjYwZjllZTJhOTA4NjAwZTdkZmIyMzE5NTUiLCJpYXQiOjE0ODQyOTc1MjksImF0X2hhc2giOiJRMmV5b3BkbktIc1QxY0VTbHdscTNRIiwic2lkIjoiOWZkYzRiMmJkNGMwY2M5MDE2NmRkMzZmYmZhMGY0MWYiLCJzdWIiOiI4ODQyMTExMyIsImF1dGhfdGltZSI6MTQ4NDI5NzUyOCwiaWRwIjoibG9jYWwiLCJhbXIiOlsicHdkIl19.jlGE9Lh5ZpU2Kne5-l9bMpJpUMUBUBDukKcIfK62h24ArI4QxVlG5mQPG0_vRRZYMtZDtkk78NDTttH5k0o21igvWAtoApxHGZv4NvnriVEWOFTidlPSRrcB77o__Gv0fnngSIJ03bENxRkZHEcTBP312kJk2khy-8kSvykYNhh0HFvkCKa8oGHu0Q_DJQH1xZIKqoTbPCzGQSLuqObNmg6Xkvg4h38MHOh1LIEt1PPhYkCJSBA6fceqtmv95hXwPTi4DY4-OwRpvm-_FHQvnjEfRPyltus_fJKijWIVSNWKqvZxxGG2hvBFsBgnvLu6L5mqfqQiOJYQDWhtenuMjg";

    public static RsaSecurityKey CreateKey()
    {
        var rsa = RSA.Create();

#if NET472
            if (rsa.KeySize < 2048)
            {
                rsa.Dispose();
                rsa = new RSACryptoServiceProvider(2048);
            }
#endif
        RsaSecurityKey key = null;
#if NET472
            if (rsa is RSACryptoServiceProvider) 
            {
                var parameters = rsa.ExportParameters(includePrivateParameters: true);
                key = new RsaSecurityKey(parameters);
                        
                rsa.Dispose();
            }   
#endif
        if (key == null)
        {
            key = new RsaSecurityKey(rsa);
        }

        key.KeyId = "1";
        return key;
    }

    public static global::IdentityModel.Jwk.JsonWebKeySet CreateKeySet(RsaSecurityKey key)
    {
        var parameters = key.Rsa?.ExportParameters(false) ?? key.Parameters;
        var exponent = Base64Url.Encode(parameters.Exponent);
        var modulus = Base64Url.Encode(parameters.Modulus);

        var webKey = new global::IdentityModel.Jwk.JsonWebKey
        {
            Kty = "RSA",
            Use = "sig",
            Kid = key.KeyId,
            E = exponent,
            N = modulus,
        };

        var set = new global::IdentityModel.Jwk.JsonWebKeySet();
        set.Keys.Add(webKey);
        return set;
    }

    public static string CreateJwt(RsaSecurityKey key, string issuer, string audience, params Claim[] claims)
    {
        var jwtClaims = new List<Claim>(claims);
        jwtClaims.Add(new Claim(JwtClaimTypes.IssuedAt, "now"));

        SigningCredentials credentials = null;
        if (key != null)
        {
            credentials = new SigningCredentials(key, "RS256");
        }

        var jwt = new JwtSecurityToken(
            issuer,
            audience,
            jwtClaims,
            DateTime.UtcNow,
            DateTime.UtcNow.AddHours(1),
            credentials);


        var handler = new JwtSecurityTokenHandler();
        handler.OutboundClaimTypeMap.Clear();

        return handler.WriteToken(jwt);
    }

    public static string HashData(string data)
    {
        using (var sha = SHA256.Create())
        {
            var hash = sha.ComputeHash(Encoding.ASCII.GetBytes(data));

            var leftPart = new byte[16];
            Array.Copy(hash, leftPart, 16);

            return Base64Url.Encode(leftPart);
        }
    }
}
